#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "header.h"

struct entry* lookup(char* name){

   int i=0;
   struct entry* ptr=NULL;
   char* new;
   pthread_mutex_lock(&mutex_head);
   ptr=head;
   while(ptr!=NULL){
       if (!strcmp(ptr->name,name))
       {
           pthread_mutex_unlock(&mutex_head);
           return ptr;
       }
       ptr=ptr->next;
   }

   pthread_mutex_unlock(&mutex_head);
   return ptr;
}

struct entry* replace_policy(long size){
    //Best fit replacement
    long diff=cache_size;
    struct entry* curr=head;
    struct entry* replace=NULL;
    for(;curr!=NULL;curr=curr->next){
        if (curr->size < size)  continue;
        if (diff> curr->size - size)
        {
            diff=curr->size-size;
            replace=curr;
        }
    }
    if (replace==NULL)
    {
        printf("#######All the Cache entry are too small#####");
    }
    else
        printf("##########Replace %s########\n",replace->name);
    return replace;
}


void add(char* host,char* path, char* date, char* content, long size,long sec){

    pthread_mutex_lock(&mutex_cache_left);
    long left=cache_left;


    while(left<size &&head!=NULL )
    {
        struct entry* replace=replace_policy(size);
        if (replace==NULL)
            remove_e(head,0);
        else
            remove_e(replace,0);
        left=cache_left;
    }

    cache_left-=size;

    struct entry* ptr=(struct entry*)malloc(sizeof(struct entry));

    ptr->host=host;
    ptr->path=path;
    ptr->content=content;
    ptr->size=size;
    ptr->sec=sec;
    if (date==NULL) 
        ptr->date=NULL;
    else
        ptr->date=date;


    char* name=(char*)malloc(sizeof(char)*(strlen(host)+strlen(path)+5));
    strcpy(name,host);
    strcat(name,path);
    ptr->name=name;

    pthread_mutex_lock(&mutex_head);
    ptr->next=head;
    head=ptr;

    //printf("@@@@@@@Add %s, Cache left %li@@@@@@@@@\n",ptr->name,cache_left);

    pthread_mutex_unlock(&mutex_head);
    pthread_mutex_unlock(&mutex_cache_left);


}

void remove_e(struct entry* ptr,int enableLock){

    //lock the # of cache_left first, then lock the head

    if(enableLock) pthread_mutex_lock(&mutex_cache_left);
    cache_left+=ptr->size;
    

    pthread_mutex_lock(&mutex_head);

    //printf("@@@@@@@Remove %s,Cache left%li@@@@@@@@\n",ptr->name,cache_left);

    free(ptr->content);
    free(ptr->date);
    free(ptr->host);
    free(ptr->name);
    free(ptr->path);

    struct entry* curr=head;

    if (curr==ptr)
        head=ptr->next;
    else
    {
        while(curr->next!=ptr)  curr=curr->next;
        curr->next=ptr->next;
    }

    free(ptr);

    pthread_mutex_unlock(&mutex_head);

    if(enableLock) pthread_mutex_unlock(&mutex_cache_left);


}

